{-# LANGUAGE FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses,NoMonomorphismRestriction #-}
{-# OPTIONS_GHC -XUndecidableInstances -XOverlappingInstances #-}

module SliceADT
  ( LabelType, SLabels  
  , Slices
  , lkpSli, mrgSli
  , updSli, updSli2, updSlices  
  , xtdSli, xtdSli2, xtdSlices    
  , unionLkpSli 
  )
 where
 
import Data.List (delete,foldl') 
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import Data.Map (Map)
import qualified Data.Map as Map



type Name = String
type LabelType = Int
type SLabels = IntSet  
type Slices = Map Name SLabels 

{-
instance Show Slices where
 show ds = showSlices ds
 
showSlices :: Slices -> String
showSlices = showSlices' IntSet.toList
showSlices2 = showSlices' id

showSlices' toList ds | ds == Map.empty = "\nThe slice table is NULL !" 
                      | otherwise = "\n Variable      SrcLineNumbers  "  ++ 
                                    "\n------------------------------\n" ++ res
       where res = unlines . buildTable $ mapSnds (concatInter "," .(map show). toList) ds'
             ds' = Map.toAscList ds
-}

-- lkpSli n ds = list of labels that reference n in ds
lkpSli :: Name -> Slices -> SLabels
lkpSli x ls =  -- Map.findWithDefault IntSet.empty x ls
    case Map.lookup x ls of
     Nothing -> IntSet.empty  --[]
     Just ls -> ls

-- updSli n ls ds = updates ds assigning ls to n
-- {-# SCC "UpdateSlice" #-}
updSli :: Name -> SLabels -> Slices -> Slices
updSli =  Map.insert   

updSli2 :: [Name] -> SLabels -> Slices -> Slices           
updSli2 args ls ds
           = foldl'
              (\r arg -> updSli arg ls r) ds args

updSlices :: [Name] -> [SLabels] -> Slices -> Slices
updSlices args [] ds = ds
--           = foldl'
--              (\r arg -> updSli arg IntSet.empty r) ds args              
updSlices args lcs ds
           = foldl'
              (\r (arg,lc)-> updSli arg lc r) ds
                [(arg,lc) | (arg,lc) <- zip args lcs]

-- xtdSli n ls ds = extends ds assigning ls to n
xtdSli :: Name -> SLabels -> Slices -> Slices
xtdSli = Map.insertWith' IntSet.union 
--xtdSli x ls [] = [(x,ls)]
--xtdSli x ls ((y,ls'):ds) 
--    | x == y    = (x,IntSet.union ls ls'):ds
--    | otherwise = (y,ls'):xtdSli x ls ds
    
xtdSli2 :: [Name] -> SLabels -> Slices -> Slices
xtdSli2 args ls ds
           = foldl'
              (\r arg -> xtdSli arg ls r) ds args

xtdSlices :: [Name] -> [SLabels] -> Slices -> Slices
xtdSlices args [] ds = ds
--           = foldr(\arg r -> xtdSli arg IntSet.empty r) ds args
xtdSlices args lcs ds
           = foldl'
              (\r (arg,lc) -> xtdSli arg lc r) ds
                [(arg,lc) | (arg,lc) <- zip args lcs]
              
-- mrgSli ss ss' = merges two slices ss and ss'
mrgSli ::  Slices -> Slices -> Slices
mrgSli = Map.unionWith IntSet.union
--    foldr (\(x,ls) r -> xtdSli x ls r) ss

-- unionLkpSli ns ls = union of the slices corresponding
--                     to each variable v in ns 
unionLkpSli :: [Name] -> Slices -> SLabels
unionLkpSli vs ls = IntSet.unions [lkpSli v ls | v <- vs]   -- {-# SCC "Label" #-} 
{-# INLINE unionLkpSli #-}
 


-- test
s1 :: Slices
s1 = Map.fromList [("ta",IntSet.fromList [1]),("bd",IntSet.fromList [1,3,2,3,4,4,4,4,4,4]),
      ("0cd",IntSet.fromList [2,3,1]),("d",IntSet.fromList [4])]

s2 = updSli2 ["ta","hello"] IntSet.empty s1
